﻿/*
  Copyright © Alexander G. Bykin, Russia 2009-2010
  This source is subject to the Microsoft Public License (Ms-PL).
  Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
  All other rights reserved.
*/

namespace System.Windows.Controls.Data
{
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Reflection;
    using System.ServiceModel.DomainServices.Client;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Runtime.Serialization;
    using System.Windows.Media;
    using System.Windows.Automation.Peers;
    using System.Windows.Automation.Provider;

    #region Public Class DelegateCommand

    public class DelegateCommand<T> : ICommand
    {
        private Func<T, bool> m_canExecute;
        private Action<T> m_executeAction;
        private bool m_canExecuteCache;
        public event EventHandler CanExecuteChanged;

        public DelegateCommand(Action<T> executeAction, Func<T, bool> canExecute)
        {
            m_executeAction = executeAction;
            m_canExecute = canExecute;
        }

        #region ICommand Members

        public bool CanExecute(object parameter)
        {
            bool temp = m_canExecute((T)parameter);
            if (m_canExecuteCache != temp)
            {
                m_canExecuteCache = temp;
                if (CanExecuteChanged != null)
                {
                    CanExecuteChanged(this, new EventArgs());
                }
            }
            return m_canExecuteCache;
        }

        public void Execute(object parameter)
        {
            m_executeAction((T)parameter);
        }

        #endregion
    }

    #endregion

    #region Public Class ObservableValue<T>

    /// <summary>
    /// Simple replacement for XAML DynamicResource (because it's not supported even by SilverLight4)
    /// Example of usage:
    ///   public class DynaString : ObservableValue<string> { };
    ///   public class DynaStrList: ObservableValue<List<string>> { };
    ///   ((DynaStrList)this.Resources["MyList"]).Value = new List<string> { "N", "Y" };
    ///   ((DynaString)this.Resources["MyString"]).Value = "AAA";
    ///
    /// In XAML:
    ///   <UserControl.Resources>
    ///     <local:DynaStrList x:Key="MyList"/>
    ///     <local:DynaString  x:Key="MyString"/>
    ///   </UserControl.Resources>
    ///
    /// </summary>
    public class ObservableValue<T> : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private T v;
        public T Value
        {
            get { return this.v; }
            set
            {
                if ((this.v == null) && (value != null) || (this.v != null) && !this.v.Equals(value))
                {
                    this.v = value;
                    var handlers = this.PropertyChanged;
                    if (handlers != null)
                    {
                        handlers(this, new PropertyChangedEventArgs("Value"));
                    }
                }
            }
        }
    }

    public class DynaCommand : ObservableValue<ICommand> { };
    public class DynaString : ObservableValue<string> { };
    public class DynaObject : ObservableValue<object> { };

    #endregion

    public delegate bool CanCancelEventHandler(object sender, EventArgs e);

    public enum EntityFieldsOrder { Alphabetical, DisplayOrder }

    public static class Utilities
    {
        #region Public Methods

        #region Public Method AllChildren

        /// <summary>
        /// Example of usage:
        /// FrameworkElement cellContent = (sender as DataGrid).CurrentColumn.GetCellContent((sender as DataGrid).SelectedItem);
        /// foreach (var c in cellContent.AllChildren<Control>((child) => !(child is DataGrid))) { names.Add(c.Name) }
        /// </summary>
        public static List<T> AllChildren<T>(this FrameworkElement ele, Func<DependencyObject, bool> whereFunc = null) where T : class
        {
          if (ele == null) return null;
          var output = new List<T>();
          var c = VisualTreeHelper.GetChildrenCount(ele);
          for (var i = 0; i < c; i++)
          {
            var ch = VisualTreeHelper.GetChild(ele, i);
            if (whereFunc != null && !whereFunc(ch)) continue;
            if (ch is T) output.Add(ch as T);
            if (!(ch is FrameworkElement)) continue;
            output.AddRange((ch as FrameworkElement).AllChildren<T>(whereFunc));
          }
          return output;
        }

        #endregion

        #region Public Method Press

        public static void Press(this Button btn)
        {
          ButtonAutomationPeer peer = new ButtonAutomationPeer(btn);
          IInvokeProvider ip = (IInvokeProvider)peer;
          ip.Invoke();
        }

        #endregion

        #region Public Method ParseStringAsListOfString

        public static List<string> ParseStringAsListOfString(string source)
        {
            return (!string.IsNullOrWhiteSpace(source)) ? (from r in source.Replace(" ", "").Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries).ToList<string>() select r.ToLower()).ToList() : new List<string>(); //Case Insensitive modified by Ahmed Kapasi
        }

        #endregion

        #region Public Method DDSFilterDescriptorsEqual

        public static bool DDSFilterDescriptorsEqual(this DomainDataSource dds, List<DataGridFilterItem> dataGridFilterItems)
        {
            if (dds == null) return false;
            if ((dataGridFilterItems == null || dataGridFilterItems.Count == 0) && dds.FilterDescriptors.Count > 0)
                return false;
            //
            foreach (var fi in dataGridFilterItems)
            {
                var found = false;
                foreach (var fd in dds.FilterDescriptors)
                {
                    if (FilterDescriptorsEqual(fi.FilterDescriptor, fd))
                    {
                        found = true;
                        break;
                    }
                }
                if (!found) return false;
            }
            return true;
        }

        #endregion

        #region Public Method GetDDSFilterDescriptorsCopy

        /// <summary>
        /// Get FilterDescriptors from the DomainDataSource
        /// </summary>
        /// <param name="dds">DomainDataSource</param>
        /// <param name="DomainEntityFieldList">List of DomainEntityField user-frendly field names</param>
        /// <param name="DataGridFilterItems">DataGridFilterItem</param>
        public static void GetDDSFilterDescriptorsCopy(this DomainDataSource dds, List<DomainEntityField> DomainEntityFieldList, List<DataGridFilterItem> DataGridFilterItems)
        {
            if (dds == null)
            {
                return;
            }

            DataGridFilterItems.Clear();
            foreach (var item in dds.FilterDescriptors)
            {
                DataGridFilterItems.Add(
                    new DataGridFilterItem(DomainEntityFieldList)
                    {
                        FilterDescriptor = GetFilterDescriptorCopy(item)
                    });
            }
        }

        #endregion

        #region Public Method SetToDDSFilterDescriptorsCopy

        /// <summary>
        /// Set FilterDescriptors to the DomainDataSource
        /// </summary>
        /// <param name="dds">DomainDataSource</param>
        /// <param name="DataGridFilterItems">DataGridFilterItem</param>
        public static void SetToDDSFilterDescriptorsCopy(this DomainDataSource dds, List<DataGridFilterItem> DataGridFilterItems)
        {
            if (dds == null)
            {
                return;
            }

            dds.FilterDescriptors.Clear();
            foreach (var item in DataGridFilterItems)
            {
                dds.FilterDescriptors.Add(GetFilterDescriptorCopy(item.FilterDescriptor));
            }
        }

        #endregion

        #region Public Method DDSSortDescriptorsEqual

        public static bool DDSSortDescriptorsEqual(this DomainDataSource dds, List<DataGridSortItem> dataGridSortItems)
        {
            if (dds == null) return false;
            if ((dataGridSortItems == null || dataGridSortItems.Count == 0) && dds.SortDescriptors.Count > 0)
                return false;
            if (dataGridSortItems.Count != dds.SortDescriptors.Count) return false;
            //
            for (int i = 0; i < dataGridSortItems.Count; i++)
            {
                var si = dataGridSortItems[i];
                if (!SortDescriptorsEqual(si.SortDescriptor, dds.SortDescriptors[i])) return false;
            }
            return true;
        }

        #endregion

        #region Public Method GetDDSSortDescriptorsCopy

        /// <summary>
        /// Get SortDescriptors from the DomainDataSource
        /// </summary>
        /// <param name="dds">DomainDataSource</param>
        /// <param name="DomainEntityFieldList">List of DomainEntityField user-frendly field names</param>
        /// <param name="DataGridSortItems"></param>
        public static void GetDDSSortDescriptorsCopy(this DomainDataSource dds, List<DomainEntityField> DomainEntityFieldList, List<DataGridSortItem> DataGridSortItems)
        {
            if (dds == null)
            {
                return;
            }

            DataGridSortItems.Clear();
            foreach (var item in dds.SortDescriptors)
            {
                DataGridSortItems.Add(
                    new DataGridSortItem(DomainEntityFieldList)
                    {
                        SortDescriptor = GetSortDescriptorCopy(item)
                    });
            }
        }

        #endregion

        #region Public Method SetToDDSSortDescriptorsCopy

        /// <summary>
        /// Set SortDescriptors to the DomainDataSource
        /// </summary>
        /// <param name="dds">DomainDataSource</param>
        /// <param name="DataGridSortItems">DataGridSortItem</param>
        public static void SetToDDSSortDescriptorsCopy(this DomainDataSource dds, List<DataGridSortItem> DataGridSortItems)
        {
            if (dds == null)
            {
                return;
            }

            dds.SortDescriptors.Clear();
            foreach (var item in DataGridSortItems)
            {
                dds.SortDescriptors.Add(GetSortDescriptorCopy(item.SortDescriptor));
            }
        }

        #endregion

        #region Public Method DDSGroupDescriptorsEqual

        public static bool DDSGroupDescriptorsEqual(this DomainDataSource dds, List<DataGridGroupItem> dataGridGroupItems)
        {
            if (dds == null) return false;
            if ((dataGridGroupItems == null || dataGridGroupItems.Count == 0) && dds.GroupDescriptors.Count > 0)
                return false;
            if (dataGridGroupItems.Count != dds.GroupDescriptors.Count) return false;
            //
            for (int i = 0; i < dataGridGroupItems.Count; i++)
            {
                var gi = dataGridGroupItems[i];
                if (!GroupDescriptorsEqual(gi.GroupDescriptor, dds.GroupDescriptors[i])) return false;
            }
            return true;
        }

        #endregion

        #region Public Method GetDDSGroupDescriptorsCopy

        /// <summary>
        /// Get GroupDescriptors from the DomainDataSource
        /// </summary>
        /// <param name="dds">DomainDataSource</param>
        /// <param name="DomainEntityFieldList">List of DomainEntityField user-frendly field names</param>
        /// <param name="DataGridGroupItems">DataGridGroupItem</param>
        public static void GetDDSGroupDescriptorsCopy(this DomainDataSource dds, List<DomainEntityField> DomainEntityFieldList, List<DataGridGroupItem> DataGridGroupItems)
        {
            if (dds == null)
            {
                return;
            }

            DataGridGroupItems.Clear();
            foreach (var item in dds.GroupDescriptors)
            {
                DataGridGroupItems.Add(
                    new DataGridGroupItem(DomainEntityFieldList)
                    {
                        GroupDescriptor = GetGroupDescriptorCopy(item)
                    });
            }
        }

        #endregion

        #region Public Method SetToDDSGroupDescriptorsCopy

        /// <summary>
        /// Set GroupDescriptors to the DomainDataSource
        /// </summary>
        /// <param name="dds">DomainDataSource</param>
        /// <param name="DataGridGroupItems">List of DataGridGroupItem</param>
        public static void SetToDDSGroupDescriptorsCopy(this DomainDataSource dds, List<DataGridGroupItem> DataGridGroupItems)
        {
            if (dds == null)
            {
                return;
            }

            dds.GroupDescriptors.Clear();
            foreach (var item in DataGridGroupItems)
            {
                dds.GroupDescriptors.Add(GetGroupDescriptorCopy(item.GroupDescriptor));
            }
        }

        #endregion

        #region Public Method GetFilterDescriptorCopy

        /// <summary>
        /// Copy and return the FilterDescriptor
        /// </summary>
        /// <param name="FilterDescriptor">FilterDescriptor</param>
        /// <returns>FilterDescriptor</returns>
        private static FilterDescriptor GetFilterDescriptorCopy(FilterDescriptor FilterDescriptor)
        {
            return new FilterDescriptor() { PropertyPath = FilterDescriptor.PropertyPath, Operator = FilterDescriptor.Operator, Value = FilterDescriptor.Value, IgnoredValue = FilterDescriptor.IgnoredValue, IsCaseSensitive = FilterDescriptor.IsCaseSensitive };
        }

        #endregion

        #region Public Method ObjectsEqual

        private static bool ObjectsEqual(object o1, object o2)
        {
            return (o1 == null && o2 == null ||
                    o1 != null && o2 != null && o1.ToString().Equals(o2.ToString()));
        }

        #endregion

        #region Public Method FilterDescriptorsEqual

        private static bool FilterDescriptorsEqual(FilterDescriptor descr1, FilterDescriptor descr2)
        {
            if (descr1 == null && descr2 == null) return true;
            if (descr1 == null && descr2 != null || descr1 != null && descr2 == null) return false;
            return descr1.PropertyPath.Equals(descr2.PropertyPath) &&
                   descr1.Operator == descr2.Operator &&
                   ObjectsEqual(descr1.Value, descr2.Value) &&
                   ObjectsEqual(descr1.IgnoredValue, descr2.IgnoredValue) &&
                   descr1.IsCaseSensitive == descr2.IsCaseSensitive;
        }

        #endregion

        #region Public Method GetSortDescriptorCopy

        /// <summary>
        /// Copy and return SortDescriptor
        /// </summary>
        /// <param name="SortDescriptor">SortDescriptor</param>
        /// <returns>SortDescriptor</returns>
        private static SortDescriptor GetSortDescriptorCopy(SortDescriptor SortDescriptor)
        {
            return new SortDescriptor() { PropertyPath = SortDescriptor.PropertyPath, Direction = SortDescriptor.Direction };
        }

        private static bool SortDescriptorsEqual(SortDescriptor descr1, SortDescriptor descr2)
        {
            if (descr1 == null && descr2 == null) return true;
            if (descr1 == null && descr2 != null || descr1 != null && descr2 == null) return false;
            return descr1.PropertyPath.Equals(descr2.PropertyPath) &&
                   descr1.Direction == descr2.Direction;
        }

        #endregion

        #region Public Method GetGroupDescriptorCopy

        /// <summary>
        /// Copy and return GroupDescriptor
        /// </summary>
        /// <param name="GroupDescriptor">GroupDescriptor</param>
        /// <returns>GroupDescriptor</returns>
        public static GroupDescriptor GetGroupDescriptorCopy(GroupDescriptor GroupDescriptor)
        {
            return new GroupDescriptor() { PropertyPath = GroupDescriptor.PropertyPath };
        }

        private static bool GroupDescriptorsEqual(GroupDescriptor descr1, GroupDescriptor descr2)
        {
            if (descr1 == null && descr2 == null) return true;
            if (descr1 == null && descr2 != null || descr1 != null && descr2 == null) return false;
            return descr1.PropertyPath.Equals(descr2.PropertyPath);
        }

        #endregion

        #region Public Method DataGridRefreshItemsSource

        public static void DataGridRefreshItemsSource(this DataGrid dg, IEnumerable ItemsSource)
        {
            if (dg == null)
            {
                return;
            }

            dg.ItemsSource = null;
            dg.ItemsSource = ItemsSource;

            if (ItemsSource != null && dg.SelectedIndex == -1)
            {
                bool empty = true;
                foreach (var i in ItemsSource)
                {
                    empty = false;
                    break;
                }
                if (!empty) dg.SelectedIndex = 0;
            }
        }

        #endregion

        #region Public Method GetListOfDomainEntityFields

        /// <summary>
        /// Get the list of DomainEntityField from DependencyProperty FieldsSource using IncludeFieldList and ExcludeFieldList.
        /// </summary>
        /// <returns>Return List of DomainEntityField.</returns>
        public static List<DomainEntityField> GetListOfDomainEntityFields(DomainDataSource dds, List<string> includeFieldList, List<string> excludeFieldList, DomainEntityFieldCollection domainEntityFieldCollection)
        {
            List<DomainEntityField> result = new List<DomainEntityField>();
            IDictionary<string, BindingMode> bindingModes = new Dictionary<string, BindingMode>();

            if (System.Diagnostics.Debugger.IsAttached)
            {
                System.Diagnostics.Debug.WriteLine(string.Format("IncludeFieldList: {0}", string.Join(",", includeFieldList)));
                System.Diagnostics.Debug.WriteLine(string.Format("ExcludeFieldList: {0}", string.Join(",", excludeFieldList)));
            }

            if (dds == null || string.IsNullOrWhiteSpace(dds.QueryName))
            {
                if (System.Diagnostics.Debugger.IsAttached)
                {
                    System.Diagnostics.Debug.WriteLine("DomainDataSource is Null or QueryName is empty, next work of 'GetListOfDomainEntityFields' method can't be done, exiting.");
                }
                return result;
            }

            #region Special thanks for Kyle McClellan

            var entityType = GetEntityTypeFromDomainContextByQueryName(dds.DomainContext, dds.QueryName);

            #endregion

            List<PropertyInfo> propertyInfos = entityType.GetEntityMembers();

            if (propertyInfos == null)
            {
                if (System.Diagnostics.Debugger.IsAttached)
                {
                    System.Diagnostics.Debug.WriteLine("EntityType is not have properties.");
                }
                return result;
            }

            if (System.Diagnostics.Debugger.IsAttached)
            {
                System.Diagnostics.Debug.WriteLine(string.Format("Entity: '{0}'", entityType.Name));
            }

            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                if (propertyInfo.GetIndexParameters().Length > 0)
                {
                    // Don't generate anything for indexed properties.
                    continue;
                }

                DisplayAttribute displayAttribute = GetPropertyDisplayAttribute(entityType.Name, propertyInfo, bindingModes);

                string displayName = string.Empty;
                string propertyPath = string.Empty;
                Type propertyType = null;
                int orderId = 0;

                DomainEntityField domainEntityField = domainEntityFieldCollection.FirstOrDefault(r => r.PropertyPath.ToLower() == propertyInfo.Name.ToLower());

                GetEntityFieldInfo(propertyInfo, domainEntityField, displayAttribute, out displayName, out propertyPath, out propertyType, out orderId);

                if (propertyInfo.GetCustomAttributes(true).Where(r => r.GetType() == typeof(AssociationAttribute)).Count() > 0)
                {
                    Type relatedPropertyTypeForPrepare = null;

                    int relatedOrderId = orderId;
                    string relatedEntityDisplayName = displayName;
                    string relatedEntityName = propertyInfo.Name; //PropertyName
                    string relatedEntityTypeName = propertyInfo.PropertyType.Name; //PropertyTypeName

                    if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.BaseType == typeof(Object)) //here we have related EntityCollection
                    {
                        relatedPropertyTypeForPrepare = GetEntityTypeFromGeneric(propertyInfo.PropertyType);

                        if (System.Diagnostics.Debugger.IsAttached)
                        {
                            System.Diagnostics.Debug.WriteLine(string.Format("Related EntityCollection: Name='{0}', TypeName='{1}', DisplayName='{2}', orderId='{3}'", relatedEntityName, relatedPropertyTypeForPrepare.Name, relatedEntityDisplayName, relatedOrderId));
                        }
                    }

                    if (!propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.BaseType == typeof(Entity)) // here we have related Entity
                    {
                        if (string.IsNullOrWhiteSpace(relatedEntityTypeName))
                        {
                            if (System.Diagnostics.Debugger.IsAttached)
                            {
                                System.Diagnostics.Debug.WriteLine(string.Format("Cant get RelatedEntity TypeName of Entity '{0}'", propertyInfo.Name));
                                continue;
                            }
                        }

                        if (System.Diagnostics.Debugger.IsAttached)
                        {
                            System.Diagnostics.Debug.WriteLine(string.Format("Related Entity: Name='{0}', TypeName='{1}', DisplayName='{2}', orderId='{3}'", relatedEntityName, relatedEntityTypeName, relatedEntityDisplayName, relatedOrderId));
                        }

                        relatedPropertyTypeForPrepare = propertyInfo.PropertyType;
                    }

                    if (relatedPropertyTypeForPrepare == null)
                    {
                        if (System.Diagnostics.Debugger.IsAttached)
                        {
                            System.Diagnostics.Debug.WriteLine("Related Entity/EntityCollection is null, continue parsing.");
                        }
                        continue;
                    }

                    foreach (var relatedEntityField in relatedPropertyTypeForPrepare.GetEntityMembers())
                    {
                        string relatedPropertyPath = string.Format("{0}.{1}", relatedEntityName, relatedEntityField.Name);
                        DomainEntityField relatedDomainEntityField = domainEntityFieldCollection.FirstOrDefault(r => r.PropertyPath.ToLower() == relatedPropertyPath.ToLower());
                        DisplayAttribute entityDisplayAttribute = GetPropertyDisplayAttribute(relatedEntityTypeName, relatedEntityField, bindingModes);
                        GetEntityFieldInfo(relatedEntityField, relatedDomainEntityField, entityDisplayAttribute, out displayName, out propertyPath, out propertyType, out orderId);

                        string debugMessage = string.Format("RelatedEntityField: displayName='{0}', propertyPath='{1}', propertyType='{2}', orderId='{3}'", displayName, relatedPropertyPath, propertyType.Name, relatedOrderId);

                        if (displayName == relatedEntityField.Name)
                        {
                            displayName = string.Format("{0}.{1}", relatedEntityDisplayName, relatedEntityField.Name);
                        }
                        else
                        {
                            // relatedDomainEntityField.DisplayName has higher priority, and could be already preprocessed some way (localization, readability, ...)
                            if (relatedDomainEntityField == null || displayName != relatedDomainEntityField.DisplayName)
                              displayName = string.Format("{0}.{1}", relatedEntityDisplayName, displayName);
                        }

                        if (IsEntityFieldCanAdded(relatedPropertyPath, includeFieldList, excludeFieldList))
                        {
                            debugMessage += " IsAdded";
                            result.Add(new DomainEntityField() { PropertyPath = relatedPropertyPath, DisplayName = displayName, PropertyType = propertyType, OrderId = relatedOrderId });
                        }
                        else
                        {
                            debugMessage += " Is in ExcludeFieldList";
                        }

                        if (System.Diagnostics.Debugger.IsAttached)
                        {
                            System.Diagnostics.Debug.WriteLine(debugMessage);
                        }
                    }

                    //}
                }
                else if (propertyInfo.GetCustomAttributes(true).Where(r => r.GetType() == typeof(DataMemberAttribute)).Count() > 0)
                {
                    string debugMessage = string.Format("EntityField: displayName='{0}', propertyPath='{1}', propertyType='{2}', orderId='{3}'", displayName, propertyPath, propertyType.Name, orderId);

                    if (IsEntityFieldCanAdded(propertyPath, includeFieldList, excludeFieldList))
                    {
                        debugMessage += " IsAdded";
                        result.Add(new DomainEntityField() { PropertyPath = propertyPath, DisplayName = displayName, PropertyType = propertyType, OrderId = orderId });
                    }
                    else
                    {
                        debugMessage += " Is in ExcludeFieldList";
                    }

                    if (System.Diagnostics.Debugger.IsAttached)
                    {
                        System.Diagnostics.Debug.WriteLine(debugMessage);
                    }
                }
            }

            return result.OrderBy(r => r.OrderId).ToList();
        }

        #endregion

        #region Public Method GetListOfFilterOperationNames

        public readonly static FilterOperator[] DefaultFilterOpOrder =
          new[] {
            FilterOperator.IsEqualTo,
            FilterOperator.IsNotEqualTo,
            FilterOperator.StartsWith,
            FilterOperator.Contains
          };

        /// <summary>
        /// Gets the list of FilterOperator names.
        /// </summary>
        /// <returns>Return IList<string> of FilterOperator names.</returns>
        public static IList<string> GetListOfFilterOperatorNames(FilterOperatorLocalizationCollection folc, List<FilterOperator> filterOperatorListByFieldType)
        {
            IList<string> result = new List<string>();

            var fields = from field in typeof(FilterOperator).GetFields()
                         where field.IsLiteral
                         orderby (
                           DefaultFilterOpOrder.
                             Select((op, idx) => new {Op = op, Idx = idx }).
                             Where(x => x.Op.ToString().Equals(field.Name)).
                             Select(x => x.Idx).DefaultIfEmpty(int.MaxValue).FirstOrDefault()
                         )
                         select field;

            bool IsFOLFound = false;

            if (folc != null)
            {
                foreach (FilterOperatorLocalization fol in folc)
                {
                    if (filterOperatorListByFieldType.Contains(fol.Operator))
                    {
                        result.Add(fol.Localization);
                    }
                }
                IsFOLFound = true;
            }

            if (!IsFOLFound)
            {
                foreach (var fieldInfo in fields)
                {
                    if (filterOperatorListByFieldType.Contains((FilterOperator)Enum.Parse(typeof(FilterOperator), fieldInfo.Name, true)))
                    {
                        result.Add(fieldInfo.Name);
                    }
                }
            }

            return result;
        }

        #endregion

        #region Public Method GetListOfSortDirectionNames

        /// <summary>
        /// Gets the list of SortDirection names.
        /// </summary>
        /// <returns>Return IList<string> of SortDirection names.</returns>
        public static IList<string> GetListOfSortDirectionNames(SortDirectionLocalizationCollection sdlc)
        {
            IList<string> result = new List<string>();

            var fields = from field in typeof(ListSortDirection).GetFields()
                         where field.IsLiteral
                         select field;

            bool IsSDLFound = false;

            if (sdlc != null)
            {
                foreach (SortDirectionLocalization sdl in sdlc)
                {
                    result.Add(sdl.Localization);
                }
                IsSDLFound = true;
            }

            if (!IsSDLFound)
            {
                foreach (var fieldInfo in fields)
                {
                    result.Add(fieldInfo.Name);
                }
            }

            return result;
        }

        #endregion

        #region Public Method GetFilterOperatorByLocalization

        /// <summary>
        /// Get ListSortDirection value by Localization or first operator from list.
        /// </summary>
        /// <param name="localization">The FilterOperator string value.</param>
        /// <param name="localizationList">The FilterOperatorLocalizationCollection that defined in control.</param>
        /// <returns></returns>
        public static FilterOperator GetFilterOperatorByLocalization(string localization, FilterOperatorLocalizationCollection localizationList)
        {
            FilterOperator result = FilterOperator.Contains;

            bool IsFOLFound = false;

            if (localizationList != null && localizationList.Count > 0)
            {
                try
                {
                    FilterOperatorLocalization fol = localizationList.Where(r => r.Localization.ToLower() == localization.ToLower()).FirstOrDefault();
                    if (CheckIsFilterOperatorDefined(fol.Operator))
                    {
                        result = fol.Operator;
                        IsFOLFound = true;
                    }
                }
                catch { }
            }

            if (!IsFOLFound)
            {
                result = (FilterOperator)Enum.Parse(typeof(FilterOperator), localization, true);
            }

            return result;
        }

        #endregion

        #region Public Method GetLocalizationByFilterOperator

        /// <summary>
        /// Get Localization by FilterOperator or original FilterOperator name.
        /// </summary>
        /// <param name="filterOperator">The FilterOperator</param>
        /// <param name="localizationList">The FilterOperatorLocalizationCollection that defined in control.</param>
        /// <returns></returns>
        public static string GetLocalizationByFilterOperator(FilterOperator filterOperator, FilterOperatorLocalizationCollection localizationList)
        {
            string result = filterOperator.ToString();

            if (localizationList != null && localizationList.Count > 0)
            {
                result = localizationList.Where(r => r.Operator == filterOperator).FirstOrDefault().Localization;
            }
            return result;
        }

        #endregion

        #region Public Method GetSortDirectionByLocalization

        /// <summary>
        /// Get ListSortDirection value by Localization or first descriptor from list.
        /// </summary>
        /// <param name="localization">The Localization string value.</param>
        /// <param name="localizationList">The SortDirectionLocalizationCollection that defined in control.</param>
        /// <returns>ListSortDirection</returns>
        public static ListSortDirection GetSortDescriptorByLocalization(string localization, SortDirectionLocalizationCollection localizationList)
        {
            ListSortDirection result = ListSortDirection.Ascending;

            bool IsSDLFound = false;

            if (localizationList != null && localizationList.Count > 0)
            {
                try
                {
                    SortDirectionLocalization sdl = localizationList.Where(r => r.Localization.ToLower() == localization.ToLower()).FirstOrDefault();
                    if (CheckIsSortDirectionDefined(sdl.Direction))
                    {
                        result = sdl.Direction;
                        IsSDLFound = true;
                    }
                }
                catch { }
            }

            if (!IsSDLFound)
            {
                result = (ListSortDirection)Enum.Parse(typeof(ListSortDirection), localization, true);
            }

            return result;
        }

        #endregion

        #region Public Method GetLocalizationBySortDirection

        /// <summary>
        /// Get Localization by SortDescriptor or original SortDescriptor name.
        /// </summary>
        /// <param name="sortDirection">The SortDescriptor.</param>
        /// <param name="localizationList">The SortDirectionLocalizationCollection.</param>
        /// <returns>String value.</returns>
        public static string GetLocalizationBySortDirection(ListSortDirection sortDirection, SortDirectionLocalizationCollection localizationList)
        {
            string result = sortDirection.ToString();
            if (localizationList != null && localizationList.Count > 0)
            {
                result = localizationList.Where(r => r.Direction == sortDirection).FirstOrDefault().Localization;
            }
            return result;
        }

        #endregion

        #region Public Method CheckIsFilterOperatorDefined

        /// <summary>
        /// Check FilterOperator is defined in original list.
        /// </summary>
        /// <param name="filterOperator">The FilterOperator value</param>
        /// <returns></returns>
        public static bool CheckIsFilterOperatorDefined(FilterOperator filterOperator)
        {
            bool result = false;

            if (Enum.IsDefined(typeof(FilterOperator), filterOperator))
            {
                result = true;
            }

            return result;
        }

        #endregion

        #region Public Method CheckIsSortDirectionDefined

        /// <summary>
        /// Check ListSortDirection is defined in original list.
        /// </summary>
        /// <param name="sortDirection">The ListSortDirection value</param>
        /// <returns>bool</returns>
        public static bool CheckIsSortDirectionDefined(ListSortDirection sortDirection)
        {
            bool result = false;

            if (Enum.IsDefined(typeof(ListSortDirection), sortDirection))
            {
                result = true;
            }

            return result;
        }

        #endregion

        #region Private Method IsEntityFieldCanAdded

        /// <summary>
        /// Check the EntityField can be added
        /// </summary>
        /// <param name="displayName">Field DisplayName</param>
        /// <param name="propertyPath">Field PropertyPath</param>
        /// <param name="includeFieldList">List of Field that must be Included</param>
        /// <param name="excludeFieldList">List of Field that must be Excluded</param>
        /// <returns>Return true if (includeFieldList AND excludeFieldList) is empty OR not exists at excludeFieldList</returns>
        public static bool IsEntityFieldCanAdded(string propertyPath, List<string> includeFieldList, List<string> excludeFieldList)
        {
            if ((includeFieldList == null || includeFieldList.Count == 0) && (excludeFieldList == null || excludeFieldList.Count == 0))
            {
                return true;
            }

            #region PropertyPath Case Insensitive

            propertyPath = propertyPath.ToLower(); //Added by Ahmed Kapasi

            #endregion

            if (string.IsNullOrWhiteSpace(propertyPath))
            {
                return false;
            }

            #region RelatedEntity Case Insensitive

            string relatedAll = (propertyPath.Contains('.')) ? string.Format("{0}.*", propertyPath.Split('.').FirstOrDefault()).ToLower() : propertyPath.ToLower(); //Modified by Ahmed Kapasi

            #endregion

            bool includeField = includeFieldList.Contains(propertyPath);
            bool includeFieldRelatedAll = includeFieldList.Contains(relatedAll);
            bool excludeField = excludeFieldList.Contains(propertyPath);
            bool excludeFieldRelatedAll = excludeFieldList.Contains(relatedAll);


            if (includeField || includeFieldRelatedAll)
            {
                if (System.Diagnostics.Debugger.IsAttached)
                {
                    System.Diagnostics.Debug.WriteLine(string.Format("Method: IsEntityFieldCanAdded; PropertyPath: '{0}' is can be added.", propertyPath));
                }
                return true;
            }

            //If ExcludeFieldList is empty, so we need only see IncludeFieldList right?
            if (excludeFieldList.Count == 0)
            {
                if (System.Diagnostics.Debugger.IsAttached)
                {
                    System.Diagnostics.Debug.WriteLine(string.Format("Method: IsEntityFieldCanAdded; PropertyPath: '{0}' is can not be added, because it is not in IncludeFieldList and not in ExludeFieldList", propertyPath));
                }
                return false;
            }

            if (!excludeField && !excludeFieldRelatedAll)
            {
                if (System.Diagnostics.Debugger.IsAttached)
                {
                    System.Diagnostics.Debug.WriteLine(string.Format("Method: IsEntityFieldCanAdded; PropertyPath: '{0}' is can be added.", propertyPath));
                }
                return true;
            }

            if (System.Diagnostics.Debugger.IsAttached)
            {
                System.Diagnostics.Debug.WriteLine(string.Format("Method: IsEntityFieldCanAdded; PropertyPath: '{0}' is can not be added.", propertyPath));
            }
            return false;
        }

        #endregion

        #endregion

        #region Private Methods

        #region Private Method GetEntityTypeFromDomainContextByQueryName

        private static Type GetEntityTypeFromDomainContextByQueryName(DomainContext domainContext, string queryName)
        {
            queryName = (queryName.Contains("Query")) ? queryName : string.Format("{0}Query", queryName);

            MethodInfo operationInfo = domainContext.GetType().GetMethods().Where(m => (m.Name == queryName)).FirstOrDefault();

            if (operationInfo == null)
            {
                if (System.Diagnostics.Debugger.IsAttached)
                {
                    System.Diagnostics.Debug.WriteLine(string.Format("DomainContext is not have QueryMethod '{0}'.", queryName));
                }
                throw new Exception(string.Format("DomainContext is not have QueryMethod '{0}'.", queryName));
            }

            if (!typeof(EntityQuery).IsAssignableFrom(operationInfo.ReturnType))
            {
                throw new NotImplementedException("Support for return types other than EntityQuery is not implemented.");
            }

            return GetEntityTypeFromGeneric(operationInfo.ReturnType);
        }

        #endregion

        #region Private Method GetEntityTypeFromGeneric

        private static Type GetEntityTypeFromGeneric(Type type)
        {
            if (!type.IsGenericType)
            {
                throw new Exception("Type is not a Generic, cant get GenericArguments");
            }

            #region Special thanks for Kyle McClellan

            return type.GetGenericArguments()[0];

            #endregion
        }

        #endregion

        #region Private Method GetEntityMembers

        /// <summary>
        /// Gets the Entity fields
        /// </summary>
        /// <param name="type">EntityType</param>
        /// <returns>List of PropertyInfo</returns>
        private static List<PropertyInfo> GetEntityMembers(this Type type)
        {
            /*return type.GetProperties(BindingFlags.Public | BindingFlags.Instance).
                Where(r => r.CanRead && r.CanWrite && (r.PropertyType == typeof(bool) || r.PropertyType == typeof(int) || r.PropertyType == typeof(decimal) || r.PropertyType == typeof(byte) || r.PropertyType == typeof(string) || r.PropertyType == typeof(DateTime) || r.PropertyType.BaseType == typeof(Entity) || r.PropertyType.BaseType == typeof(EntityCollection<Entity>))).ToList();*/

            #region Special thanks for Colin Blair & sladapter

            BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.Instance;
            var qry = from p in type.GetProperties(bindingAttr)
                      where (p.GetCustomAttributes(typeof(DataMemberAttribute), true).Length > 0 ||
                      p.GetCustomAttributes(typeof(AssociationAttribute), true).Length > 0)
                      select p;
            return qry.ToList();

            #endregion
        }

        #endregion

        #region Private Method GetPropertyDisplayAttribute

        /// <summary>
        /// Gets EntityField DisplayAttribute
        /// </summary>
        /// <param name="entityName">The name of Entity</param>
        /// <param name="propertyInfo">The EntityField</param>
        /// <param name="bindingModes">The list of Bindings</param>
        /// <returns></returns>
        private static DisplayAttribute GetPropertyDisplayAttribute(string entityName, PropertyInfo propertyInfo, IDictionary<string, BindingMode> bindingModes)
        {
            DisplayAttribute displayAttribute =
                    propertyInfo.GetCustomAttributes(typeof(DisplayAttribute), true) //inherit
                    .Cast<DisplayAttribute>()
                    .FirstOrDefault();

            if (displayAttribute == null ||
                !displayAttribute.GetAutoGenerateField().HasValue ||
                displayAttribute.GetAutoGenerateField().Value == true)
            {
                if (propertyInfo.GetSetMethod() != null)
                {
                    if (!bindingModes.ContainsKey(string.Format("{0}.{1}", entityName, propertyInfo.Name)))
                    {
                        bindingModes.Add(string.Format("{0}.{1}", entityName, propertyInfo.Name), BindingMode.TwoWay);
                    }
                }
                else
                {
                    if (!bindingModes.ContainsKey(string.Format("{0}.{1}", entityName, propertyInfo.Name)))
                    {
                        bindingModes.Add(string.Format("{0}.{1}", entityName, propertyInfo.Name), BindingMode.OneWay);
                    }
                }
            }

            return displayAttribute;
        }

        #endregion

        #region Private Method GetEntityFieldInfo

        /// <summary>
        /// Gets EntityField info: displayName, properyPath, propertyType
        /// </summary>
        /// <param name="propertyInfo"></param>
        /// <param name="domainEntityField"></param>
        /// <param name="displayAttribute"></param>
        /// <param name="displayName">out displayName</param>
        /// <param name="propertyPath">out propertyPath</param>
        /// <param name="propertyType">out propertyType</param>
        private static void GetEntityFieldInfo(PropertyInfo propertyInfo, DomainEntityField domainEntityField, DisplayAttribute displayAttribute, out string displayName, out  string propertyPath, out Type propertyType, out int orderId)
        {
            if (displayAttribute != null)
            {
                int displayOrderId = 0;

                try
                {
                    displayOrderId=(int)displayAttribute.GetOrder();
                }
                catch
                {
                }

                //GET Entity field name from DomainContext
                if (domainEntityField == null)
                {
                    displayName = displayAttribute.GetName();
                    if (string.IsNullOrEmpty(displayName))
                    {
                        displayName = displayAttribute.GetShortName();
                        if (string.IsNullOrEmpty(displayName))
                            displayName = propertyInfo.Name;
                    }
                    propertyPath = propertyInfo.Name;
                    propertyType = propertyInfo.PropertyType;
                    orderId = displayOrderId;
                }
                else
                {
                    displayName = domainEntityField.DisplayName;
                    domainEntityField.DisplayName = displayName;
                    domainEntityField.PropertyType = propertyInfo.PropertyType;
                    propertyPath = domainEntityField.PropertyPath;
                    propertyType = domainEntityField.PropertyType;
                    orderId = displayOrderId;
                }
            }
            else
            {
                if (domainEntityField == null)
                {
                    displayName = propertyInfo.Name;
                    propertyPath = propertyInfo.Name;
                    propertyType = propertyInfo.PropertyType;
                    orderId = 0;
                }
                else
                {
                    displayName = domainEntityField.DisplayName;
                    domainEntityField.PropertyType = propertyInfo.PropertyType;
                    propertyPath = domainEntityField.PropertyPath;
                    propertyType = domainEntityField.PropertyType;
                    orderId = domainEntityField.OrderId;
                }
            }
        }

        #endregion

        #endregion
    }
}
